﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Castle.DynamicProxy;
using Micro.Core.ApiConsumer.ActionAttributes;
using Micro.Core.ApiConsumer.Context;
using Micro.Core.ApiConsumer.Extensions;
using Micro.Core.ApiConsumer.ParameterAttributes;

namespace Micro.Core.ApiConsumer
{
    /// <summary>
    /// api描述缓存，对于相同的接口，描述应该一致
    /// </summary>
    static class ApiDescriptorCache
    {
        /// <summary>
        /// 缓存字典
        /// </summary>
        private static readonly ConcurrentDictionary<IInvocation, ApiActionDescriptor> cache;

        /// <summary>
        /// Castle相关上下文
        /// </summary>
        static ApiDescriptorCache()
        {
            cache = new ConcurrentDictionary<IInvocation, ApiActionDescriptor>(new IInvocationComparer());
        }

        /// <summary>
        /// 从缓存获得ApiActionDescriptor
        /// </summary>
        /// <param name="invocation">拦截内容</param>
        /// <returns></returns>
        public static ApiActionDescriptor GetApiActionDescriptor(IInvocation invocation)
        {
            return cache.GetOrAdd(invocation, GetActionDescriptor);
        }

        /// <summary>
        /// 从拦截内容获得ApiActionDescriptor
        /// </summary>
        /// <param name="invocation">拦截内容</param>
        /// <returns></returns>
        private static ApiActionDescriptor GetActionDescriptor(IInvocation invocation)
        {
            var method = invocation.Method;
            var returnType = method.ReturnType;
            var actionAttributes = method.FindDeclaringAttributes<ApiActionAttribute>(true)
                .OrderBy(item => item.OrderIndex)
                .ToArray();
            var parameterDescriptors = method.GetParameters().Select((p, i) => GetParameterDescriptor(p, i)).ToArray();
            var apiActionDescriptor = new ApiActionDescriptor
            {
                Name = method.Name,
                Attributes = actionAttributes,
                Parameters = parameterDescriptors,
                Return = returnType
            };
            return apiActionDescriptor;
        }

        /// <summary>
        /// 获取接口具体参数描述实例
        /// </summary>
        /// <param name="parameterInfo">参数详情</param>
        /// <param name="index">参数对应索引</param>
        /// <returns></returns>
        private static ApiParameterDescriptor GetParameterDescriptor(ParameterInfo parameterInfo, int index)
        {
            return new ApiParameterDescriptor
            {
                Name = parameterInfo.Name,
                Index = index,
                ParameterAttribute = parameterInfo.GetAttributes<ApiParameterAttribute>(true).FirstOrDefault(),
                ParameterType = parameterInfo.ParameterType
            };
        }

        /// <summary>
        /// IInvocation对象的比较器
        /// </summary>
        private class IInvocationComparer : IEqualityComparer<IInvocation>
        {
            /// <summary>
            /// 是否相等
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public bool Equals(IInvocation x, IInvocation y)
            {
                return x.Method.Equals(y.Method);
            }

            /// <summary>
            /// 获取哈希码
            /// </summary>
            /// <param name="obj"></param>
            /// <returns></returns>
            public int GetHashCode(IInvocation obj)
            {
                return obj.Method.GetHashCode();
            }
        }
    }
}
